#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/usb/hcd.h>
#include <linux/pm_runtime.h>
#include <linux/pm.h>
#include "xhci_ts.h"


#define PCI_VENDOR_ID_FRESCO_LOGIC	0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK	0x1000
#define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400	0x1400
#define PCI_VENDOR_ID_ETRON		0x1b6f
#define PCI_DEVICE_ID_ASROCK_P67	0x7023
static const char hcd_name[] = "xhci_ts";

/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
	/* handle any USB 3.0 xHCI controller */
	PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
	//.driver_data =	(unsigned long) &xhci_pci_hc_driver,
	},
	{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);

static struct xhci_hcd *xhci;
static const struct hc_driver xhci_pci_hc_driver = {
	.description =		hcd_name,
	.product_desc =		"xHCI Host Controller",
	.hcd_priv_size =	sizeof(struct xhci_hcd *),
	/*
	 * generic hardware linkage
	 */
///	.irq =			xhci_irq,
	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
};
static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct hc_driver *driver;
	struct usb_hcd *hcd;
	int retval;
	printk("zoucao xhci_ts pci probe\n");

	driver = &xhci_pci_hc_driver;
	xhci = kzalloc(sizeof(struct xhci_hcd) ,GFP_KERNEL);
	xhci->hcd = usb_create_shared_hcd(driver, &dev->dev,
				pci_name(dev), hcd);
	if(!hcd)
	{
		printk("zoucao %s create hcd err\n", __func__);
	}

	retval = usb_add_hcd(hcd, dev->irq,
			IRQF_SHARED);

	if(retval)
	{
		printk("zoucao %d create hcd err\n", retval);
	}

	return 0;
}

static void xhci_pci_remove(struct pci_dev *dev)
{
	usb_remove_hcd(xhci->hcd);
	usb_put_hcd(xhci->hcd);
	kfree(xhci);
}

/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
	.name =		(char *) hcd_name,
	.id_table =	pci_ids,

	.probe = xhci_pci_probe,
	.remove = xhci_pci_remove,
	/* suspend and resume implemented later */

	//.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM_SLEEP
//	.driver = {
//		.pm = &usb_hcd_pci_pm_ops
//	},
#endif
};

static int ts_driver_init(void)
{
	//pci_register_driver(&xhci_pci_driver);
	xhci_hcd_init();
	printk("zoucao xhci_ts entry\n");
	return 0;
}

static void ts_driver_exit(void)
{
	//pci_unregister_driver(&xhci_pci_driver);
	xhci_hcd_cleanup();
	printk("zoucao xhci_ts exit\n");
}

module_init(ts_driver_init);
module_exit(ts_driver_exit);
MODULE_LICENSE("GPL");
